<?php declare(strict_types=1);

/**
 * @author      guosir
 * @copyright   2023-2025 owner
 **/

namespace Srv\Apps\Apis\Skit\Ctl;

use Srv\Apps\Proto\DTO\Skit\SkitCategoryAddDTO;
use Srv\Apps\Proto\DTO\Skit\SkitCategoryEditDTO;
use Srv\Apps\Proto\DTO\Skit\SkitCategoryListDTO;
use Srv\Apps\Proto\Enum\YesOrNoEnum;
use Srv\Apps\Proto\VO\Skit\SkitCategoryListVO;
use Srv\Apps\Proto\VO\Skit\SkitCategoryVO;
use Srv\Libs\Common\CommArray;
use Srv\Libs\Common\CommJson;
use Srv\Libs\Common\CommTime;
use Srv\Libs\Frame\ControllerAbstract;
use Srv\Libs\Frame\Page;
use Srv\Libs\Storage\DataMysql;

final class SkitCategoryCtl extends ControllerAbstract
{
    private ?DataMysql $DbAuto              = null;     // DB-Write

    /**
     * @return static
     * tag
     */
    final public static function tag():self
    {
        $thisObject                         = self::tagGet();
        if($thisObject instanceof self){
            $thisObject->DbAuto             = self::getDbAuto();
        }
        return $thisObject;
    }

    /**
     * @param int $skcyId
     * @return array
     * getSkitCategorySrc
     */
    public function getSkitCategorySrc(int $skcyId):array
    {
        if($skcyId < 1) return [];
        $isFail             = false;
        $categoryRecord     = $this->DbAuto->getDataOne('SELECT skcy_id, skcy_name, skcy_id_top, skcy_id_parent, skcy_id_path, skcy_show, skcy_create_time, skcy_update_time FROM '.$this->DbAuto->getTableNameAll('skit_category').' WHERE skcy_id='.$skcyId.' AND skcy_delete=0', $isFail);
        if($isFail || !isset($categoryRecord['skcy_id'])) return [];
        return $categoryRecord;
    }

    /**
     * @param array $skcyIdList
     * @return array
     * getSkitCategorySrcBatch
     */
    public function getSkitCategorySrcBatch(array $skcyIdList):array
    {
        if(count($skcyIdList) < 1) return [];
        $isFail         = false;
        $list           = $this->DbAuto->getData('SELECT skcy_id, skcy_name, skcy_id_top, skcy_id_parent, skcy_id_path, skcy_show, skcy_create_time, skcy_update_time FROM '.$this->DbAuto->getTableNameAll('skit_category').' WHERE skcy_id IN('.implode(',', $skcyIdList).') AND skcy_delete=0', $isFail);
        $listData       = [];
        if(!$isFail && CommArray::isForeach($list)) foreach ($list as $item){
            $skcyIdItem             = intval($item['skcy_id']??0);
            if($skcyIdItem < 1) continue;
            $listData[$skcyIdItem]  = $item;
        }
        return $listData;
    }

    /**
     * @param array $skcyIdList
     * @return array
     * getSkitCategorySrcBatch
     */
    public function getSkitCategoryBatch(array $skcyIdList):array
    {
        $list       = $this->getSkitCategorySrcBatch($skcyIdList);
        $listData   = [];
        if(CommArray::isForeach($list)){
            foreach ($list as $item){
                $skcyIdItem             = intval($item['skcy_id']??0);
                if($skcyIdItem < 1) continue;
                $SkitCategoryVO         = $this->getSkitCategoryVO($item);
                if(!($SkitCategoryVO instanceof SkitCategoryVO)) continue;
                $listData[$skcyIdItem]  = $SkitCategoryVO;
            }
        }
        return $listData;
    }

    /**
     * @param Page $Page
     * @param array $whereData
     * @return SkitCategoryListVO|null
     * getSkitCategoryList
     */
    public function getSkitCategoryList(Page $Page, array $whereData): ?SkitCategoryListVO
    {
        $limitString        = $Page->getLimitString();
        $whereString        = ' WHERE skcy_delete=0 ';
        // 检索条件
        if(count($whereData) > 0)foreach ($whereData as $key => $val){
            switch ($key){
                case SkitCategoryListDTO::_skcyId:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'skcy_id='. intval($val);
                    break;
                case SkitCategoryListDTO::_name:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'skcy_name LIKE \'%'.$this->DbAuto->getRealEscapeString($val).'%\'';
                    break;
                case SkitCategoryListDTO::_show:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'skcy_show='. intval($val);
                    break;
            }
        }
        $isFail             = false;
        $sql                = 'SELECT SQL_CALC_FOUND_ROWS skcy_id, skcy_name, skcy_id_top, skcy_id_parent, skcy_id_path, skcy_show, skcy_create_time, skcy_update_time FROM '.$this->DbAuto->getTableNameAll('skit_category').$whereString.' ORDER BY skcy_id DESC '.$limitString;
        $categoryRecordList = $this->DbAuto->getData($sql, $isFail);
        $totalNum           = $this->DbAuto->getDataInt('SELECT FOUND_ROWS() as num', 'num');
        if($isFail) return null;
        $SkitCategoryVOList = [];
        if(CommArray::isForeach($categoryRecordList)) {
            $skcyIdTopList              = array_unique(array_map('intval', array_column($categoryRecordList, 'skcy_id_top')));
            $skcyIdParentList           = array_unique(array_map('intval', array_column($categoryRecordList, 'skcy_id_parent')));
            $categorySrcList            = $this->getSkitCategorySrcBatch(array_merge_recursive($skcyIdTopList, $skcyIdParentList));
            foreach($categoryRecordList as $categoryRecord){
                $skcyIdItem             = intval($categoryRecord['skcy_id']);
                if($skcyIdItem < 1) continue;
                $SkitCategoryVO         = $this->getSkitCategoryVO($categoryRecord);
                if(!($SkitCategoryVO instanceof SkitCategoryVO)) continue;
                $skcyIdTopItem          = intval($categoryRecord['skcy_id_top']);
                $skcyIdParentItem       = intval($categoryRecord['skcy_id_parent']);
                $SkitCategoryTopVO      = $this->getSkitCategoryVO($categorySrcList[$skcyIdTopItem]??[]);
                if($SkitCategoryTopVO instanceof SkitCategoryVO) $SkitCategoryVO->setCategoryTop($SkitCategoryTopVO);
                $SkitCategoryParentVO   = $this->getSkitCategoryVO($categorySrcList[$skcyIdParentItem]??[]);
                if($SkitCategoryParentVO instanceof SkitCategoryVO) $SkitCategoryVO->setCategoryParent($SkitCategoryParentVO);
                $SkitCategoryVOList[]   = $SkitCategoryVO;
            }
        }
        $SkitCategoryListVO = new SkitCategoryListVO();
        $SkitCategoryListVO->setList($SkitCategoryVOList);
        $SkitCategoryListVO->setPage($Page->getPageVO($totalNum));
        return $SkitCategoryListVO;
    }

    /**
     * @param int $skcyId
     * @return SkitCategoryVO|null
     * getSkitCategoryInfo
     */
    public function getSkitCategoryInfo(int $skcyId):?SkitCategoryVO
    {
        $categorySrc    = $this->getSkitCategorySrc($skcyId);
        if(!isset($categorySrc['skcy_id'])) return null;
        return $this->getSkitCategoryVO($categorySrc);
    }

    /**
     * @param array $categoryRecord
     * @return SkitCategoryVO|null
     * getSkitCategoryVO
     */
    public function getSkitCategoryVO(array $categoryRecord):?SkitCategoryVO
    {
        $skcyId                 = intval($categoryRecord['skcy_id']??0);
        if($skcyId < 1) return null;
        $SkitCategoryVO         = new SkitCategoryVO();
        $SkitCategoryVO->setSkcyId($skcyId);
        $SkitCategoryVO->setName(trim($categoryRecord['skcy_name']));
        $skcyIdTop              = intval($categoryRecord['skcy_id_top']);
        $SkitCategoryVO->setSkcyIdTop($skcyIdTop);
        $skcyIdParent           = intval($categoryRecord['skcy_id_parent']);
        $SkitCategoryVO->setSkcyIdParent($skcyIdParent);
        $SkitCategoryVO->setShow(YesOrNoEnum::parseValue($categoryRecord['skcy_show']));
        $SkitCategoryVO->setCreateTime(intval($categoryRecord['skcy_create_time']));
        $SkitCategoryVO->setUpdateTime(intval($categoryRecord['skcy_update_time']));
        return $SkitCategoryVO;
    }

    /**
     * @param array $setData
     * @return int
     * 新增短剧类别
     */
    public function skitCategoryAdd(array $setData):int
    {
        if(count($setData) < 1) return 0;
        $setString      = '';
        foreach ($setData as $key => $val){
            switch ($key){
                case SkitCategoryAddDTO::_name:
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_name=\''.$this->DbAuto->getRealEscapeString($val).'\'';
                    break;
                case SkitCategoryAddDTO::_skcyIdParent:
                    $node           = $this->getCategoryParentNode(intval($val));
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_id_parent='.$node['skcyIdParent'];
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_id_top='.$node['skcyIdTop'];
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_id_path=\''.$this->DbAuto->getRealEscapeString($node['skcyIdPath']).'\'';
                    break;
                case SkitCategoryAddDTO::_show:
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_show='.intval($val);
                    break;
            }
        }
        if(strlen($setString) < 1) return 0;
        $currTime   = CommTime::getTimeStamp(0);
        $isFail     = false;
        $sql        = 'INSERT INTO '.$this->DbAuto->getTableNameAll('skit_category').' SET '.$setString.', skcy_delete=0, skcy_create_time='.$currTime.', skcy_update_time='.$currTime;
        $skcyId     = $this->DbAuto->getDataId($sql, $isFail);
        if($isFail || $skcyId < 1) return 0;
        return $skcyId;
    }

    /**
     * @param int $skcyId
     * @return array
     * getCategoryParentNode
     */
    public function getCategoryParentNode(int $skcyId):array
    {
        $node           = ['skcyIdTop' => 0, 'skcyIdParent' => 0, 'skcyIdPath' => '[]'];
        if($skcyId < 1) return $node;
        $categorySrc    = $this->getSkitCategorySrc($skcyId);
        if(isset($categorySrc['skcy_id'])){
            $node['skcyIdTop']      = intval($categorySrc['skcy_id_top']);
            $node['skcyIdParent']   = intval($categorySrc['skcy_id']);
            if($node['skcyIdTop'] < 1 && $node['skcyIdParent'] > 0) $node['skcyIdTop'] = $node['skcyIdParent'];
            $skcyIdPathList         = CommJson::decodeArray($categorySrc['skcy_id_path']);
            $skcyIdPathList[]       = $skcyId;
            $node['skcyIdPath']     = CommJson::encodeArray($skcyIdPathList);
        }
        return $node;
    }

    /**
     * @param int $skcyId
     * @param array $setData
     * @return bool
     * 编辑短剧类别
     */
    public function skitCategoryEdit(int $skcyId, array $setData):bool
    {
        if($skcyId < 1 || count($setData) < 1) return false;
        $setString      = '';
        foreach ($setData as $key => $val){
            switch ($key){
                case SkitCategoryEditDTO::_name:
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_name=\''.$this->DbAuto->getRealEscapeString($val).'\'';
                    break;
                case SkitCategoryEditDTO::_skcyIdParent:
                    $node           = $this->getCategoryParentNode(intval($val));
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_id_parent='.$node['skcyIdParent'];
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_id_top='.$node['skcyIdTop'];
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_id_path=\''.$this->DbAuto->getRealEscapeString($node['skcyIdPath']).'\'';
                    break;
                case SkitCategoryEditDTO::_show:
                    $setString      .= (strlen($setString) > 0 ? ', ' : '') . 'skcy_show='.intval($val);
                    break;
            }
        }
        if(strlen($setString) < 1) return false;
        $isFail         = false;
        $currTime       = CommTime::getTimeStamp(0);
        $sql            = 'UPDATE '.$this->DbAuto->getTableNameAll('skit_category').' SET '.$setString.', skcy_update_time='.$currTime.' WHERE skcy_id='.$skcyId.' AND skcy_delete=0';
        if($this->DbAuto->getDataNum($sql, $isFail) < 1 || $isFail) return false;
        return true;
    }
}